package com.bifang.module.file.core.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.extra.ssh.Sftp;
import com.bifang.engine.assistant.core.enums.BoolEnum;
import com.bifang.engine.assistant.core.exception.AppException;
import com.bifang.module.file.common.vo.FileClassVO;
import com.bifang.module.file.common.vo.FileInfoVO;
import com.bifang.module.file.common.util.Encode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

/** Sftp工具类 */
@Component
public class FileSftpUtil {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    // 默认路径
    @Value("${system.config.file.default.sftp.ip}")
    private String defaultIp;

    @Value("${system.config.file.default.sftp.port}")
    private Integer defaultPort;

    @Value("${system.config.file.default.sftp.user}")
    private String defaultUser;

    @Value("${system.config.file.default.sftp.password}")
    private String defaultPassword;

    @Value("${system.config.file.default.sftp.path}")
    private String defaultPath;

    @Autowired private FileCommonUtil fileCommonUtil;

    /** sftp上传 */
    public Boolean upload(File file, FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        getBastPath(fileClassVO);
        Sftp sftp = this.getSftp(fileClassVO);
        fileCommonUtil.initFile(file, fileClassVO, fileInfoVO);
        String path =
                fileCommonUtil.getPath(fileClassVO.getFileBasePath(), fileInfoVO.getFilePath());
        if (sftp.exist(path)) {
            if (fileInfoVO.getForceFlag()) {
                sftp.delFile(path);
            } else {
                return true;
            }
        }
        // 校验文件是否可以上传
        fileCommonUtil.checkFile(fileInfoVO.getFileSuffix(), fileInfoVO.getFileSize(), fileClassVO);

        String fileName = getFileName(fileInfoVO);
        if (StringUtils.isNotBlank(fileInfoVO.getEncryptionFlag())) {
            if (BoolEnum.TRUE.getType().endsWith(fileInfoVO.getEncryptionFlag())) {
                fileInfoVO.setFilePassowrd(RandomUtil.randomString(5));
                new Encode(true, file, fileInfoVO.getFilePassowrd()).run();
            }
        } else {
            fileInfoVO.setEncryptionFlag(BoolEnum.FALSE.getType());
        }
        // 文件不存在 上传
        Boolean flag = true;
        fileInfoVO.setOtherStartTime(new Date());
        sftp.put(file.getAbsolutePath(), path);
        fileInfoVO.setOtherEndTime(new Date());

        return flag;
    }

    /** sftp上传 */
    public Boolean upload(byte[] file, FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        InputStream sbs = new ByteArrayInputStream(file);
        Boolean flag = true;
        try {
            flag = this.upload(sbs, fileClassVO, fileInfoVO);
        } finally {
            try {
                sbs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return flag;
    }

    /** sftp上传 */
    public Boolean upload(InputStream in, FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        Boolean flag = true;
        try {
            getBastPath(fileClassVO);
            Sftp sftp = this.getSftp(fileClassVO);
            fileCommonUtil.initFile(in, fileClassVO, fileInfoVO);
            String path =
                    fileCommonUtil.getPath(fileClassVO.getFileBasePath(), fileInfoVO.getFilePath());
            if (sftp.exist(path)) {
                if (fileInfoVO.getForceFlag()) {
                    sftp.delFile(path);
                } else {
                    return true;
                }
            }
            // 校验文件是否可以上传
            fileCommonUtil.checkFile(
                    fileInfoVO.getFileSuffix(), fileInfoVO.getFileSize(), fileClassVO);

            String fileName = getFileName(fileInfoVO);

            if (StringUtils.isNotBlank(fileInfoVO.getEncryptionFlag())) {
                if (BoolEnum.TRUE.getType().endsWith(fileInfoVO.getEncryptionFlag())) {
                    fileInfoVO.setFilePassowrd(RandomUtil.randomString(5));
                    File file = fileCommonUtil.createTempFile(in, fileName);
                    new Encode(true, file, fileInfoVO.getFilePassowrd()).run();
                    sftp.put(file.getAbsolutePath(), path);
                    // 删除临时文件
                    fileCommonUtil.delTempFile(file);
                    return flag;
                }
            } else {
                fileInfoVO.setEncryptionFlag(BoolEnum.FALSE.getType());
            }
            fileInfoVO.setOtherStartTime(new Date());
            sftp.put(in, path);
            fileInfoVO.setOtherEndTime(new Date());

        } catch (Exception e) {
            throw new AppException("上传文件失败:" + e.getMessage());
        } finally {

            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error("关闭流异常，", e);
                }
            }
        }
        return flag;
    }

    /** ftp文件下载 */
    public File download(FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        if (StringUtils.isBlank(fileInfoVO.getFilePath())) {
            return null;
        }
        getBastPath(fileClassVO);
        Sftp sftp = this.getSftp(fileClassVO);
        if (!sftp.exist(fileInfoVO.getFilePath())) {
            throw new AppException("文件不存在");
        }
        String path =
                fileCommonUtil.getPath(fileClassVO.getFileBasePath(), fileInfoVO.getFilePath());
        String fileName = fileInfoVO.getFileMd5() + "." + fileInfoVO.getFileSuffix();
        if (fileInfoVO.getForceFlag()) {
            fileCommonUtil.delTempFileDownloadByName(fileName);
        }
        File file = fileCommonUtil.createTempFileDownload(fileName);
        if (file.length() <= 0) {
            // 空文件重新下载
            sftp.download(path, file);
            // 解密文件
            if (BoolEnum.TRUE.getType().equals(fileInfoVO.getEncryptionFlag())) {
                new Encode(false, file, fileInfoVO.getFilePassowrd()).run();
            }
        }
        return file;
    }

    /** 获取base64文件 */
    public String getBase64(FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        File file = this.download(fileClassVO, fileInfoVO);
        if (file == null) {
            throw new AppException("文件不存在");
        }
        Long length = file.length();
        fileCommonUtil.checkBase64(length);
        return Base64.encode(file);
    }

    /** 删除文件 */
    public void delete(FileInfoVO fileInfoVO) {
        String path =
                fileCommonUtil.getPath(fileInfoVO.getFileBasePath(), fileInfoVO.getFilePath());
        FileClassVO fileClassVO = Convert.convert(FileClassVO.class, fileInfoVO);
        getBastPath(fileClassVO);
        Sftp sftp = this.getSftp(fileClassVO);
        if (sftp.exist(path)) {
            boolean flag = sftp.delFile(path);
            if (!flag) {
                throw new AppException("删除文件失败");
            }
        }
    }

    /** 获取sftp */
    private Sftp getSftp(FileClassVO fileClassVO) {
        String key = fileClassVO.getFileClassCode();
        if (StringUtils.isBlank(key)) {
            throw new AppException("文件分类不能为空");
        }
        String ip = fileClassVO.getFileServiceIp();
        if (StringUtils.isBlank(ip)) {
            ip = defaultIp;
        }

        Integer port = fileClassVO.getFileServicePort();
        if (port == null) {
            port = defaultPort;
        }

        String user = fileClassVO.getFileServiceUser();
        if (StringUtils.isBlank(user)) {
            user = defaultUser;
        }
        String password = fileClassVO.getFileServicePwd();
        if (StringUtils.isBlank(password)) {
            password = defaultPassword;
        }

        Sftp sftp = JschUtil.createSftp(ip, port, user, password);
        return sftp;
    }

    private String getFileName(FileInfoVO fileInfoVO) {
        return fileInfoVO.getFileMd5() + "." + fileInfoVO.getFileSuffix();
    }

    private void getBastPath(FileClassVO fileClassVO) {
        if (StringUtils.isBlank(fileClassVO.getFileBasePath())) {
            fileClassVO.setFileBasePath(defaultPath);
        }
    }
}
